/*
 * Note that this control will most likely remain as an example, and not as a
 * core Ext form control. However, the API will be changing in a future release
 * and so should not yet be treated as a final, stable API at this time.
 */

/**
 * A control that allows selection of between two Ext.ux.form.MultiSelect
 * controls.
 */

Ext.define('Ext.ux.form.ItemSelector', {
	extend : 'Ext.ux.form.MultiSelect',
	alias : ['widget.itemselectorfield', 'widget.itemselector'],
	alternateClassName : ['Ext.ux.ItemSelector'],
	requires : ['Ext.button.Button', 'Ext.ux.form.MultiSelect'],

	/**
	 * @cfg {Boolean} [hideNavIcons=false] True to hide the navigation icons
	 */
	hideNavIcons : false,

	/**
	 * @cfg {Array} buttons Defines the set of buttons that should be displayed
	 *      in between the ItemSelector fields. Defaults to
	 *      <tt>['top', 'up', 'add', 'remove', 'down', 'bottom']</tt>. These
	 *      names are used to build the button CSS class names, and to look up
	 *      the button text labels in {@link #buttonsText}. This can be
	 *      overridden with a custom Array to change which buttons are displayed
	 *      or their order.
	 */
	buttons : ['top', 'up', 'add', 'remove', 'down', 'bottom'],

	/**
	 * @cfg {Object} buttonsText The tooltips for the {@link #buttons}. Labels
	 *      for buttons.
	 */
	buttonsText : {
		top : "置顶",
		up : "上移",
		add : "添加",
		remove : "移除",
		down : "下移",
		bottom : "置底"
	},

	initComponent : function() {
		var me = this;

		me.ddGroup = me.id + '-dd';
		me.callParent();

		// bindStore must be called after the fromField has been created because
		// it copies records from our configured Store into the fromField's
		// Store
		// 11111
		me.bindStore(me.store);
	},

	createList : function(title) {
		var me = this;
		// ====================
		// if (isStore) {
		// store = me.store;
		// } else {
		// store = {
		// model : me.store.model,
		// data : []
		// };
		// }
		// ==================
		return Ext.create('Ext.ux.form.MultiSelect', {
					submitValue : false,
					flex : 1,
					dragGroup : me.ddGroup,
					dropGroup : me.ddGroup,
					title : title,
					store : {
						model : me.store.model,
						data : []
					},
					// store : store,
					displayField : me.displayField,
					disabled : me.disabled,
					listeners : {
						boundList : {
							scope : me,
							itemdblclick : me.onItemDblClick,
							drop : me.syncValue
						}
					}
				});
	},

	setupItems : function() {
		var me = this;

		me.fromField = me.createList(me.fromTitle);
		me.toField = me.createList(me.toTitle);
		// me.fromField = me.createList(me.fromTitle, true);
		// me.toField = me.createList(me.toTitle, false);

		return {
			border : false,
			layout : {
				type : 'hbox',
				align : 'stretch'
			},
			items : [me.fromField, {
						xtype : 'container',
						margins : '0 4',
						width : 22,
						layout : {
							type : 'vbox',
							pack : 'center'
						},
						items : me.createButtons()
					}, me.toField]
		};
	},

	createButtons : function() {
		var me = this, buttons = [];

		if (!me.hideNavIcons) {
			Ext.Array.forEach(me.buttons, function(name) {
						buttons.push({
									xtype : 'button',
									tooltip : me.buttonsText[name],
									handler : me['on'
											+ Ext.String.capitalize(name)
											+ 'BtnClick'],
									cls : Ext.baseCSSPrefix
											+ 'form-itemselector-btn',
									iconCls : Ext.baseCSSPrefix
											+ 'form-itemselector-' + name,
									navBtn : true,
									scope : me,
									margin : '4 0 0 0'
								});
					});
		}
		return buttons;
	},

	/**
	 * Get the selected records from the specified list.
	 * 
	 * Records will be returned *in store order*, not in order of selection.
	 * 
	 * @param {Ext.view.BoundList}
	 *            list The list to read selections from.
	 * @return {Ext.data.Model[]} The selected records in store order.
	 * 
	 */
	getSelections : function(list) {
		var store = list.getStore();

		return Ext.Array.sort(list.getSelectionModel().getSelection(),
				function(a, b) {
					a = store.indexOf(a);
					b = store.indexOf(b);

					if (a < b) {
						return -1;
					} else if (a > b) {
						return 1;
					}
					return 0;
				});
	},

	onTopBtnClick : function() {
		var list = this.toField.boundList, store = list.getStore(), selected = this
				.getSelections(list);

		store.suspendEvents();
		store.remove(selected, true);
		store.insert(0, selected);
		store.resumeEvents();
		list.refresh();
		this.syncValue();
		list.getSelectionModel().select(selected);
	},

	onBottomBtnClick : function() {
		var list = this.toField.boundList, store = list.getStore(), selected = this
				.getSelections(list);

		store.suspendEvents();
		store.remove(selected, true);
		store.add(selected);
		store.resumeEvents();
		list.refresh();
		this.syncValue();
		list.getSelectionModel().select(selected);
	},

	onUpBtnClick : function() {
		var list = this.toField.boundList, store = list.getStore(), selected = this
				.getSelections(list), rec, i = 0, len = selected.length, index = 0;

		// Move each selection up by one place if possible
		store.suspendEvents();
		for (; i < len; ++i, index++) {
			rec = selected[i];
			index = Math.max(index, store.indexOf(rec) - 1);
			store.remove(rec, true);
			store.insert(index, rec);
		}
		store.resumeEvents();
		list.refresh();
		this.syncValue();
		list.getSelectionModel().select(selected);
	},

	onDownBtnClick : function() {
		var list = this.toField.boundList, store = list.getStore(), selected = this
				.getSelections(list), rec, i = selected.length - 1, index = store
				.getCount()
				- 1;

		// Move each selection down by one place if possible
		store.suspendEvents();
		for (; i > -1; --i, index--) {
			rec = selected[i];
			index = Math.min(index, store.indexOf(rec) + 1);
			store.remove(rec, true);
			store.insert(index, rec);
		}
		store.resumeEvents();
		list.refresh();
		this.syncValue();
		list.getSelectionModel().select(selected);
	},

	onAddBtnClick : function() {
		var me = this, selected = me.getSelections(me.fromField.boundList);

		me.moveRec(true, selected);
		me.toField.boundList.getSelectionModel().select(selected);
	},

	onRemoveBtnClick : function() {
		var me = this, selected = me.getSelections(me.toField.boundList);

		me.moveRec(false, selected);
		me.fromField.boundList.getSelectionModel().select(selected);
	},

	moveRec : function(add, recs) {
		var me = this, fromField = me.fromField, toField = me.toField, fromStore = add
				? fromField.store
				: toField.store, toStore = add
				? toField.store
				: fromField.store;

		fromStore.suspendEvents();
		toStore.suspendEvents();
		fromStore.remove(recs);
		toStore.add(recs);
		fromStore.resumeEvents();
		toStore.resumeEvents();

		fromField.boundList.refresh();
		toField.boundList.refresh();

		me.syncValue();
	},

	// Synchronizes the submit value with the current state of the toStore
	syncValue : function() {
		var me = this;
		me.mixins.field.setValue.call(me, me.setupValue(me.toField.store
						.getRange()));
	},

	onItemDblClick : function(view, rec) {
		this.moveRec(view === this.fromField.boundList, rec);
	},

	setValue : function(value) {
		var me = this, fromField = me.fromField, toField = me.toField, fromStore = fromField.store, toStore = toField.store, selected;

		// Wait for from store to be loaded
		if (!me.fromStorePopulated) {
			me.fromField.store.on({
						load : Ext.Function.bind(me.setValue, me, [value]),
						single : true
					});
			return;
		}

		value = me.setupValue(value);
		me.mixins.field.setValue.call(me, value);

		selected = me.getRecordsForValue(value);

		// Clear both left and right Stores.
		// Both stores must not fire events during this process.
		fromStore.suspendEvents();
		toStore.suspendEvents();
		fromStore.removeAll();
		toStore.removeAll();

		// Reset fromStore
		me.populateFromStore(me.store);

		// Copy selection across to toStore
		Ext.Array.forEach(selected, function(rec) {
					// In the from store, move it over
					if (fromStore.indexOf(rec) > -1) {
						fromStore.remove(rec);
					}
					toStore.add(rec);
				});

		// Stores may now fire events
		fromStore.resumeEvents();
		toStore.resumeEvents();

		// Refresh both sides and then update the app layout
		Ext.suspendLayouts();
		fromField.boundList.refresh();
		toField.boundList.refresh();
		Ext.resumeLayouts(true);
	},

	onBindStore : function(store, initial) {
		var me = this;

		if (me.fromField) {
			me.fromField.store.removeAll()
			me.toField.store.removeAll();

			// Add everything to the from field as soon as the Store is loaded
			if (store.getCount()) {
				me.populateFromStore(store);
			} else {
				me.store.on('load', me.populateFromStore, me);
			}
		}
	},

	populateFromStore : function(store) {
		var fromStore = this.fromField.store;

		// Flag set when the fromStore has been loaded
		this.fromStorePopulated = true;

		fromStore.add(store.getRange());

		// setValue waits for the from Store to be loaded
		fromStore.fireEvent('load', fromStore);
	},

	onEnable : function() {
		var me = this;

		me.callParent();
		me.fromField.enable();
		me.toField.enable();

		Ext.Array.forEach(me.query('[navBtn]'), function(btn) {
					btn.enable();
				});
	},

	onDisable : function() {
		var me = this;

		me.callParent();
		me.fromField.disable();
		me.toField.disable();

		Ext.Array.forEach(me.query('[navBtn]'), function(btn) {
					btn.disable();
				});
	},

	onDestroy : function() {
		this.bindStore(null);
		this.callParent();
	},
	/**
	 * 重新加载左侧Store
	 * 
	 * @author yakun
	 * @param {}
	 *            store
	 */
	restore : function(store) {
		this.fromField.store.loadData(store);
	},
	/**
	 * 获取显示值
	 * 
	 * @author yakun
	 * @return {}
	 */
	getText : function() {
		var text = "";
		Ext.Array.forEach(this.toField.store.data.items, function(item) {
					text = text + item.data.name + ";"
				});
		return text;
	}
});
